/*
 * @Author: liyxt
 * @Date: 2019-04-23 09:37:04
 * @LastEditors: Please set LastEditors
 * @LastEditTime: 2024-01-09 16:00:47
 * @Description: file content
 */
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const glob = require('glob');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const fs = require('fs');
const webpack = require('webpack');
const configJSON = require('../config.json');
const fileRules = require('./fileRules');
const { resolve, join } = require('path');

module.exports = function buildEntry({ buildPath, buildWithoutHTML, hash, mode, client, fse, srcDir = configJSON.srcDir || 'src', patchList }) {
	fse = fse === 'true' || fse === true || false;
	Array.isArray(buildWithoutHTML) && buildWithoutHTML.unshift('refer');
	let projects = [],
		plugins = [],
		entries = {},
		externals = {},
		lowCodeEntries = [],
		rules=[];
	// 遍历src下的js
	(function(callback) {
		if (Array.isArray(buildPath)) {
			buildPath.forEach(_buildPath => {
				callback(_buildPath);
			});
		} else {
			callback(buildPath);
		}
	})(function(buildPath) {
		getFiles(buildPath);
	});

	if (patchList) {
		let copyList = getCopyList(patchList);
		copyList.forEach((path) => {
			if(fs.existsSync(path)) {
				plugins.push(
					new CopyWebpackPlugin([
						// {output}/to/file.txt
						{ from: path, to: './' + path.match(/.*src\/(.*)/)[1] }
					])
				);}
		})
	} else {
		projects.forEach(e => {
			if (e === 'uapbd') {
				// guozhq让弄的，供应链特殊
				fs.existsSync(`./${srcDir}/uapbd/scmbase/public`) &&
					plugins.push(
						new CopyWebpackPlugin([{ from: `./${srcDir}/uapbd/scmbase/public`, to: `./uapbd/scmbase/public` }])
					);
				// wanghxm让弄的，hr特殊
				fs.existsSync(`./${srcDir}/uapbd/hrbase/public`) &&
					plugins.push(
						new CopyWebpackPlugin([{ from: `./${srcDir}/uapbd/hrbase/public`, to: `./uapbd/hrbase/public` }])
					);
			}
			fs.existsSync(`./${srcDir}/${e}/public`) &&
				plugins.push(
					new CopyWebpackPlugin([
						// {output}/to/file.txt
						{ from: `./${srcDir}/${e}/public`, to: `./${e}/public` }
					])
				);
		});
	}
	function getProjectConfigByPath(path) {
		let project = path.split('/')[2];
		let configPath = `./${srcDir}/${project}/config.json`;
		let isExists = fs.existsSync(configPath);
		if (isExists) {
			plugins.push(
				new CopyWebpackPlugin([{ from: `./${srcDir}/${project}/config.json`, to: `./${project}/config.json` }])
			);
			return require('.' + configPath);
		}
		return {};
	
	}
	function getFiles(buildPath) {
		let {buildEntryPath:projectBuildEntryPath=[]} = getProjectConfigByPath(buildPath);
		glob.sync(buildPath).forEach(path => {
			//  path ---为加载的每个index.js文件：./src/reva_demo/module/apply/list/index.js
			// chunk = 节点+list/card: reva_demo/module/apply/list
			// 原来移动和pc的构建判断比较严格，2207之后应差异化不大了，这里先把判断短路，看一下后面会有什么问题，没问题的话就统一改掉
			if (
				(client === 'mobile' && path.includes('/mobile_')) ||
				(client !== 'mobile' && !path.includes('/mobile_')) ||true
			) {
				// 移动端 || web端
				let chunk = path.split(`./${srcDir}/`)[1].split('/index.js')[0],
					project = chunk.split('/')[0]; // reva_demo

				//把src自定义命名下的文件层级减掉，更改第二层级，把领域名改为 extend_领域名  by bbqin
				if (fse) {
					let chunkarr = chunk.split('/');
					chunkarr[0] = 'NCCExtend';
					chunkarr[1] = `extend_${chunkarr[1]}`;
					chunk = chunkarr.join('/');
				}

				projects.includes(project) || projects.push(project);
				// 生成webpack.config.js的入口
				let configJSONPath = `./${srcDir}/` + chunk + '/config.json',
					isExists = fs.existsSync(configJSONPath),
					_hash,
					isLowCodeEntry = false;
				if (isExists) {
					// 特殊处理的
					let { hash, isLowCode, maxChunks } = require('.' + configJSONPath);
					// maxChunks，打包生成的最大chunks数量
					if (typeof maxChunks === 'number' && maxChunks > 0) {
						plugins.push(new webpack.optimize.LimitChunkCountPlugin({maxChunks}))
					}
					_hash = isLowCode? false : hash;
					if(isLowCode){
						lowCodeEntries.push(chunk);
					}
					

				}

				if (hash === 'false') {
					hash = false;
				} else if (hash === 'true') {
					hash = true;
				}

				let _chunk = ('/' + chunk + '/').toLowerCase();
				if (mode === 'development') {
					entries[`${chunk}/index`] = path;
				} else {
					if (hash) {
						// 筛选出带hash的
						if (_hash) {
							// config.json里的hash优先级高
							entries[`${chunk}/index`] = path;
						} else if (_hash !== false) {
							// 非参照页面生成hash
							if(!(
								_chunk.includes('/refer/') ||
								_chunk.includes('/ref/') ||
								_chunk.includes('/refers/') ||
								_chunk.includes('/mobile_refer/') ||
								fse
							)){
								if(projectBuildEntryPath.length>0){
									projectBuildEntryPath.includes(path) && (entries[`${chunk}/index`] = path);
								}else{ //后续增加强判断，如果没有配config.json就不出盘
									entries[`${chunk}/index`] = path;
								}
							}
						}
					} else {
						// 筛选出不带hash的
						if (_hash === false) {
							// config.json里的hash优先级高
							entries[`${chunk}/index`] = path;
						} else if (_hash !== true) {
							// 参照页面不生成hash
							(_chunk.includes('/refer/') ||
								_chunk.includes('/ref/') ||
								_chunk.includes('/refers/') ||
								_chunk.includes('/mobile_refer/') ||
								_hash === false ||
								fse) &&
								(entries[`${chunk}/index`] = path);
						}
					}
				}
				// buildWithoutHTML中的页面不生成html
				if (entries[`${chunk}/index`]) {
					let templatePath = client === 'mobile' ? './template/mobileTemplate.html' : './template/index.html';
					let configjs = ''; //额外配置的js文件
					let configcss = ''; //额外配置的css文件
					if (isExists) {
						let {
							template,
							output,
							dependjs,
							dependcss,
							dependModuleName,
							report,
							echarts,
							prodProxy,
							isLowCode,
							importParseLayout,
							specialExternals={},
							packages = [],
							schema,
							copyFile,
						} = require('.' + configJSONPath);
						isLowCodeEntry = isLowCode;
						// template: HTML模板路径
						if (template) {
							templatePath = template;
						}
						//低代码模式引用新的模板
						if(isLowCodeEntry){
							templatePath = "./template/lowcodeTemplate.html";
						}
						// output: 单独输出的文件配置
						if (output) {
							entries[`${output}/index`] = path;
						}

						if (schema) {
							entries[`${chunk}/index_schema`] = path.replace('index.js', 'index.schema.js');
						}

						if (copyFile) {
							plugins.push(
								new CopyWebpackPlugin(copyFile.map(({ from, to }) => {
									return { from: resolve(path, '../', from), to: join(chunk, to) }
								}))
							)
						}

						// report: 报表依赖
						if (report) {
							configjs += `<script src="../../../../lappreportrt/nc-report/public/vendor.js"></script>`;
							configjs += `<script src="../../../../lappreportrt/nc-report/index.js"></script>`;
							configcss += `<link rel="stylesheet" href="../../../../lappreportrt/nc-report/public/vendor.css" />`;
							configcss += `<link rel="stylesheet" href="../../../../lappreportrt/nc-report/index.css" />`;
						}
						if (echarts) {
						    // platform下已经没有echarts文件，避免404报错
				            // 	configjs += `<script src="../../../../platform/echarts.js"></script>`;
						}

						//importParseLayout :低代码解析组件
						if (importParseLayout) {
							configjs += `<script src="../../../../lowcode/light-front/runtime/main/runtime.js"></script>`;
						}

						// dependjs: 依赖的js文件配置
						if (Array.isArray(dependjs)) {
							configjs += dependjs.map(src => {
								let moduleName = /(?:\.\.\/)*([^\.]*)\.js/.exec(src);
								if (moduleName && moduleName[1]) {
									externals[moduleName[1]] = moduleName[1];
								}
								return `<script src="${src}"></script>`;
							}).join('');
							
						}

						// dependcss: 依赖的css文件配置
						if (Array.isArray(dependcss)) {
							configcss += dependcss
								.map(item => `<link rel="stylesheet" href=${item}?v=${Date.now()}>`)
								.join('');
						}


						// dependModuleName: 依赖的模块名
						if (Array.isArray(dependModuleName)) {
							// 打包时排除
							dependModuleName.forEach(item => (externals[`${item}`] = `${item}/index`));
						}

						if (Array.isArray(packages)) {
							packages.forEach(({ name, src, var: root }) => {
								if (!Array.isArray(src)) {
									src = [src]
								}

								src.forEach((e) => {
									if (/.js$/.test(e)) {
										configjs += `<script src="${e}"></script>`;
									} else if (/.css$/.test(e)) {
										configcss += `<link rel="stylesheet" href=${e}}>`
									}
								})

								
								externals[name] = root || name;
							})
						}

						// specialExternals: 特殊的排除
						externals = Object.assign(externals,specialExternals);

						plugins.push(
							new webpack.DefinePlugin({
								PROD_PROXY: JSON.stringify((mode !== 'development' && prodProxy) || '')
							})
						);
					}

					if ((!(buildWithoutHTML || []).some(e => path.includes(e)))) {
						const htmlConf = {
							filename: `${chunk}/index.html`, // 生成的html文件名，可加目录/.../.../index.html
							template: `${templatePath}`, // 模板html路径
							inject: true, //允许插件修改哪些内容，包括head与body
							chunks: [`${chunk}/index`], // 生成的html文件引入哪些js，不传的话引入所有js
							cache: true,
							templateParameters: {
								configjs: configjs, //为模板添加js
								configcss: configcss, //为模板添加css
								prefix: chunk.split('/').join('_') //css前缀
							}
						};
						if(isLowCodeEntry){
							htmlConf.chunks = [];
						 }
						plugins.push(new HtmlWebpackPlugin(htmlConf));

						//rules = fileRules({ cssSandbox: true, chunk });

					}
				}
			}
		});
	}

	let cleanOnceBeforeBuildPatterns = Object.values(entries).map(e => e.replace('index.js', '').replace(`./${srcDir}/`, ''));
	plugins.push(
		new CleanWebpackPlugin({
			cleanOnceBeforeBuildPatterns,
			cleanAfterEveryBuildPatterns: [],
			verbose: true
		})
	);
	return {
		plugins,
		entries,
		externals,
		lowCodeEntries,
		rules,
	};
};

function getCopyList(patchList) {
	if (!patchList) {
		return [];
	}

    let content = fs.readFileSync(patchList, { encoding: 'utf-8' });
	// content.replace('\r', '');

    let lines = content.split(/\r?\n/),
		group = {}, 
		currentGroup = '前端';

    lines.forEach((line) => {
        if (/\*{3}/.test(line)) {
            currentGroup = line;
        } else {
            group[currentGroup] = group[currentGroup] || [];
            line && group[currentGroup].push(line);
        }
    })

    let copyList = [];

    Object.entries(group).forEach(([name, lines]) => {
        if (name.includes('前端')) {
            let [, module] = name.match(/\*{3}\s([^|]*)\|/) || [];

            lines.forEach((line) => {
                let [type, path1, path2] = line.split(/\s+/), path = '';
                switch (type) {
                    case 'A':
                    case 'M':
                        path = path1;
                        break;
                    case 'R':
                        path = path2;
                        break;
                    default:
                        break;
                }

                if (path && !path.includes(module)) {
                    path = `src/${module}/${path}`;
                }

                if (path.includes(`${module}/public`) && !/\.js$|\.less$|\.css$/.test(path)) {
                    copyList.push(path);
                }

            })
        }
    })

	return copyList;
}
